package org.edu.common.config.pojo;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.collections4.SetUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.MethodUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * pojo utils
 *
 * @author worker-lxc
 */
@Slf4j
public class POJOUtils {
    
    private static ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * 对象转map
     *
     * @param bean 拷贝对象
     *
     * @return Map<String, Object>
     */
    public static Map<String, Object> beanToMap(Object bean) {
        if (bean == null) {
            return null;
        }
        Map<String, Object> map;
        try {
            // BeanUtil方法会出现错误，他会将所有的对象转成String输出Map，得到的value不是对应的类型对象
            map = PropertyUtils.describe(bean);
            map.remove("class");
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            throw new ChaosTransformBeanException();
        }
        return map;
    }
    
    /**
     * listBean对象转Map
     *
     * @param beanList 拷贝List
     *
     * @return List<Map < String, Object>>
     */
    public static List<Map<String, Object>> listBeantoMap(List<?> beanList) {
        List<Map<String, Object>> maplist = new ArrayList<>();
        
        if (beanList == null) {
            return maplist;
        }
        
        for (Object bean : beanList) {
            maplist.add(beanToMap(bean));
        }
        
        return maplist;
    }
    
    /**
     * map转对象BeanEx
     *
     * @param map 拷贝map对象
     *
     * @return T
     */
    public static <T> T maptoBeanEx(Map<?, ?> map, Class<T> cla) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        
        if (cla == null) {
            throw new ChaosTransformBeanException();
        }
        
        String str = JSON.toJSONString(map);
        
        return JSON.parseObject(str, cla);
    }
    
    /**
     * listMap转BeanEx
     *
     * @param mapList 拷贝集合
     * @param cla     目标类型
     *
     * @return List<T>
     */
    public static <T> List<T> listMaptoBeanEx(List<?> mapList, Class<T> cla) {
        List<T> beanList = new ArrayList<>();
        
        final boolean check = checkParams(mapList, cla);
        if (!check) {
            return beanList;
        }
        
        return JSON.parseArray(JSON.toJSONString(mapList), cla);
    }
    
    /**
     * 固定泛型转对象
     *
     * @return List<T>
     */
    public static <T> List<T> listMapGenericstoBeanEx(List<Map<String, Object>> mapList, Class<T> cla) {
        List<T> beanList = new ArrayList<>();
        
        final boolean check = checkParams(mapList, cla);
        if (!check) {
            return beanList;
        }
        
        for (Map<String, Object> map : mapList) {
            T bean = maptoBeanEx(map, cla);
            beanList.add(bean);
        }
        
        return beanList;
    }
    
    /**
     * removeNullValueS
     */
    public static Map<String, String> removeNullValueS(Map<String, String> map) {
        if (map != null) {
            Map<String, String> map2 = new HashMap<>(16);
            for (Map.Entry<String, String> entry : map.entrySet()) {
                if (entry.getValue() != null) {
                    map2.put(entry.getKey(), entry.getValue());
                }
            }
            return map2;
        }
        return null;
    }
    
    /**
     * removeNullValueO
     */
    public static Map<String, Object> removeNullValueO(Map<String, Object> map) {
        if (MapUtils.isEmpty(map)) {
            return new HashMap<>(16);
        }
        
        Map<String, Object> map2 = new HashMap<>(16);
        
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (entry.getValue() != null) {
                map2.put(entry.getKey(), entry.getValue());
            }
        }
        return map2;
    }
    
    /**
     * 属性复制 单个对象
     *
     * @param obj 拷贝对象
     * @param cla 目标类型
     *
     * @return 目标对象
     */
    public static <T> T copyProperties(Object obj, Class<T> cla) {
        if (null == obj || null == cla) {
            throw new ChaosTransformBeanException();
        }
        
        try {
            T dest = cla.newInstance();
            
            net.sf.cglib.beans.BeanCopier copier = net.sf.cglib.beans.BeanCopier.create(obj.getClass(), cla, false);
            copier.copy(obj, dest, null);
            
            return dest;
        } catch (InstantiationException | IllegalAccessException e) {
            throw new ChaosTransformBeanException();
        }
    }
    
    /**
     * 属性复制 单个对象
     *
     * @param obj 拷贝对象
     * @param cla 目标类型
     *
     * @return 目标对象
     */
    public static <T> Optional<T> copyPropertiesReturnOptional(Object obj, Class<T> cla) {
        if (null == obj) {
            return Optional.empty();
        }
        
        if (null == cla) {
            throw new ChaosTransformBeanException();
        }
        
        try {
            T dest = cla.newInstance();
            
            net.sf.cglib.beans.BeanCopier copier = net.sf.cglib.beans.BeanCopier.create(obj.getClass(), cla, false);
            copier.copy(obj, dest, null);
            
            return Optional.ofNullable(dest);
        } catch (InstantiationException | IllegalAccessException e) {
            throw new ChaosTransformBeanException();
        }
    }
    
    
    public static void copyPropertiesIfDestPropertyNull(Object src, Object dest) {
        net.sf.cglib.beans.BeanCopier copier = net.sf.cglib.beans.BeanCopier.create(src.getClass(), dest.getClass(), true);
        copier.copy(src, dest, (value, target, context) -> {
            try {
                String setMethodName = (String) context;
                String getMethodName = StringUtils.replace(setMethodName, "s", "g", 1);
                Object destProperty = MethodUtils.invokeMethod(dest, getMethodName);
                if (null == destProperty) {
                    return value;
                } else {
                    return destProperty;
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                throw new ChaosTransformBeanException();
            }
        });
    }
    
    /**
     * 属性复制 List对象
     *
     * @param objList 拷贝List集合
     * @param cla     目标类型
     *
     * @return List<T>
     */
    public static <T> List<T> listCopyProperties(List<?> objList, Class<T> cla) {
        List<T> destList = new ArrayList<>();
        
        final boolean check = checkParams(objList, cla);
        if (!check) {
            return destList;
        }
        
        for (Object obj : objList) {
            destList.add(copyProperties(obj, cla));
        }
        
        return destList;
    }
    
    /**
     * 参数复制 Set对象
     */
    public static <T> Set<T> setCopyProperties(Set<?> objSet, Class<T> cla) {
        if (objSet == null) {
            return SetUtils.emptySet();
        }
        
        List<T> destList = new ArrayList<>();
        
        if (objSet.isEmpty()) {
            return new HashSet<>(destList);
        }
        
        for (Object obj : objSet) {
            destList.add(copyProperties(obj, cla));
        }
        return new HashSet<>(destList);
    }
    
    private static <T> boolean checkParams(List<?> objList, Class<T> cla) {
        if (objList == null) {
            return false;
        }
        
        if (objList.isEmpty()) {
            return false;
        }
        
        if (null == cla) {
            throw new ChaosTransformBeanException();
        }
        
        return true;
    }
    
    private POJOUtils() {
    }
}
